package com.mentalhealthplatform.global.log.login;

import com.mentalhealthplatform.exception.ErrorResponse;
import com.mentalhealthplatform.exception.GlobalExceptionHandler;
import com.mentalhealthplatform.global.rbac.dto.request.AuthRequest;
import com.mentalhealthplatform.global.rbac.model.User;
import com.mentalhealthplatform.global.rbac.service.entity.BaseUserService;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;

import java.time.LocalDateTime;

@Aspect
@Component
public class LoginLogAspect {

    private static final Logger logger = LoggerFactory.getLogger(LoginLogAspect.class);

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private LoginLogRepository loginLogRepository;

    @Autowired
    private BaseUserService baseUserService;

    @Autowired
    private GlobalExceptionHandler globalExceptionHandler;

    // 定义切点：匹配带有 @LoginLogAction 注解的方法
    @Pointcut("@annotation(com.mentalhealthplatform.global.log.login.LoginLogAction)")
    public void loginLogActionPointcut() { }

    // 环绕通知：记录登录日志并处理异常
    @Around("loginLogActionPointcut()")
    public Object logLoginOperation(ProceedingJoinPoint joinPoint) throws Throwable {
        LoginLog loginLog = new LoginLog();
        loginLog.setLoginTime(LocalDateTime.now());

        // 获取 IP 地址
        String ipAddress = request.getRemoteAddr();
        loginLog.setLoginAddress(ipAddress);

        // 获取方法签名和注解信息
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        LoginLogAction loginLogAction = signature.getMethod().getAnnotation(LoginLogAction.class);
        loginLog.setLoginMessage(loginLogAction.description());

        loginLog.setBrowser("Edge");
        loginLog.setLoginLocation("成都");
        loginLog.setOperatingSystem("Windows");

        String userName = null;
        User user = null;

        try {
            // 尝试获取用户名
            Object[] args = joinPoint.getArgs();
            if (args != null && args.length > 0 && args[0] instanceof AuthRequest authRequest) {
                userName = authRequest.getUsername();
                loginLog.setLoginName(userName);
            } else {
                loginLog.setLoginName("Unknown");
                // 如果无法获取用户名，记录为异常并返回
                loginLog.setLoginStatus("EXCEPTION");
                loginLog.setLoginMessage("获取用户名失败：" + userName);
                loginLogRepository.save(loginLog);
                return buildErrorResponse("Unknown", "用户名或密码错误", HttpStatus.UNAUTHORIZED, null);
            }

            // 执行目标方法并捕获返回值
            Object result = joinPoint.proceed();

            // 尝试根据用户名查找用户对象
            user = baseUserService.findByUsername(userName).orElse(null);

            if (user != null) {
                loginLog.setUser(user);
                loginLog.setLoginStatus("SUCCESS");
                loginLog.setLoginMessage("登录成功");
            } else {
                // 如果无法找到用户，记录为异常
                loginLog.setLoginStatus("FAILURE");
                loginLog.setLoginMessage("无法找到用户：" + userName);
            }

            // 保存登录日志
            loginLogRepository.save(loginLog);
            return result;

        } catch (Throwable throwable) {
            // 处理登录失败
            loginLog.setLoginStatus("FAILURE");
            loginLog.setLoginMessage("异常: " + simplifyThrowableMessage(throwable));
            loginLogRepository.save(loginLog);

            // 统一异常处理并记录日志
            return handleLoginException(throwable, loginLog);
        }
    }

    // 异常处理逻辑，简化并集成全局异常处理流程
    private Object handleLoginException(Throwable throwable, LoginLog loginLog) {
        // 对于认证失败的异常（BadCredentialsException），直接返回 UNAUTHORIZED 错误
        if (throwable instanceof BadCredentialsException) {
            loginLog.setLoginMessage("UNAUTHORIZED: 用户名或密码错误");
            loginLogRepository.save(loginLog);

            // 构建统一的 ErrorResponse
            ErrorResponse errorResponse = new ErrorResponse(
                    "UNAUTHORIZED",
                    "用户名或密码错误",
                    HttpStatus.UNAUTHORIZED.value(),
                    LocalDateTime.now()
            );
            return new ResponseEntity<>(errorResponse, HttpStatus.UNAUTHORIZED);
        } else {
            // 对于其他类型的异常，交给全局异常处理器
            ResponseEntity<ErrorResponse> responseEntity = globalExceptionHandler.processException(throwable);
            logger.error("Exception handled: {}", simplifyThrowableMessage(throwable));

            // 记录处理后的异常消息
            loginLog.setLoginMessage(responseEntity.getBody().getMessage());
            loginLogRepository.save(loginLog);

            return responseEntity;
        }
    }

    // 构建错误响应
    private ResponseEntity<ErrorResponse> buildErrorResponse(
            String error, String detail, HttpStatus status, BindingResult bindingResult) {

        logger.error("Error Response: [{}] - Detail: {}", error, detail);
        ErrorResponse errorResponse = new ErrorResponse(error, detail, status.value(), LocalDateTime.now());

        return new ResponseEntity<>(errorResponse, status);
    }

    // 简化 Throwable 的信息
    private String simplifyThrowableMessage(Throwable throwable) {
        String message = throwable.getMessage();

        // 如果异常信息太长，截取一部分
        if (message != null && message.length() > 200) {
            message = message.substring(0, 200) + "...";
        }

        // 如果是数据库异常，且存在堆栈信息
        if (throwable instanceof DataAccessException) {
            message = "数据库操作失败: " + (message != null ? message : "未知错误");
        } else if (throwable instanceof BadCredentialsException) {
            message = "认证失败: " + (message != null ? message : "用户名或密码错误");
        } else {
            message = throwable.getClass().getSimpleName() + ": " + (message != null ? message : "未知错误");
        }

        return message;
    }
}
